-
Notifications
You must be signed in to change notification settings - Fork 48.7k
[Fizz] Outline if a boundary would add too many bytes to the next completion #33029
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Comparing: 8e9a5fc...8703f8a Critical size changesIncludes critical production bundles, as well as any change greater than 2%:
Significant size changesIncludes any change greater than 0.2%: (No significant changes) |
@@ -5098,6 +5113,7 @@ function flushPartialBoundary( | |||
destination: Destination, | |||
boundary: SuspenseBoundary, | |||
): boolean { | |||
flushedByteSize = boundary.byteSize; // Start counting bytes |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
partial boundaries should probably just get everything inlined right? They're already lower priority than everything else so if we're still trying to write we might as well skip fallbacks and just include everything possible since they aren't delaying painting
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The mental model that helps with this is imagining that this renders at high speed on the server with no back pressure but then it takes a long time over the wire.
So if the partial would inline everything then it would still block for a long time on the client before the outer content can complete.
Therefore it’s worth outlining in general in the stream. However because we flush all partials we’d end up flushing the outlined ones in this same pass which then blocks the segments that complete the parent anyway. Ideally we’d be more yieldy with the partial flushing to allow new content to come in if it’s soon that unblocks the parent boundary.
One thing I do here is ensure that each partial has its own count though so it’s more likely to inline if the parent has very little content prepared so far since in that case there’s nothing blocking.
…pletion (#33029) Follow up to #33027. This enhances the heuristic so that we accumulate the size of the currently written boundaries. Starting from the size of the root (minus preamble) for the shell. This ensures that if you have many small boundaries they don't all continue to get inlined. For example, you can wrap each paragraph in a document in a Suspense boundary to regain document streaming capabilities if that's what you want. However, one consideration is if it's worth producing a fallback at all. Maybe if it's like `null` it's free but if it's like a whole alternative page, then it's not. It's possible to have completely useless Suspense boundaries such as when you nest several directly inside each other. So this uses a limit of at least 500 bytes of the content itself for it to be worth outlining at all. It also can't be too small because then for example a long list of paragraphs can never be outlined. In the fixture I straddle this limit so some paragraphs are too small to be considered. An unfortunate effect of that is that you can end up with some of them not being outlined which means that they appear out of order. SuspenseList is supposed to address that but it's unfortunate. The limit is still fairly high though so it's unlikely that by default you'd start outlining anything within the viewport at all. I had to reduce the `progressiveChunkSize` by an order of magnitude in my fixture to try it out properly. DiffTrain build for [18212ca](18212ca)
…pletion (facebook#33029) Follow up to facebook#33027. This enhances the heuristic so that we accumulate the size of the currently written boundaries. Starting from the size of the root (minus preamble) for the shell. This ensures that if you have many small boundaries they don't all continue to get inlined. For example, you can wrap each paragraph in a document in a Suspense boundary to regain document streaming capabilities if that's what you want. However, one consideration is if it's worth producing a fallback at all. Maybe if it's like `null` it's free but if it's like a whole alternative page, then it's not. It's possible to have completely useless Suspense boundaries such as when you nest several directly inside each other. So this uses a limit of at least 500 bytes of the content itself for it to be worth outlining at all. It also can't be too small because then for example a long list of paragraphs can never be outlined. In the fixture I straddle this limit so some paragraphs are too small to be considered. An unfortunate effect of that is that you can end up with some of them not being outlined which means that they appear out of order. SuspenseList is supposed to address that but it's unfortunate. The limit is still fairly high though so it's unlikely that by default you'd start outlining anything within the viewport at all. I had to reduce the `progressiveChunkSize` by an order of magnitude in my fixture to try it out properly. DiffTrain build for [18212ca](facebook@18212ca)
…pletion (facebook#33029) Follow up to facebook#33027. This enhances the heuristic so that we accumulate the size of the currently written boundaries. Starting from the size of the root (minus preamble) for the shell. This ensures that if you have many small boundaries they don't all continue to get inlined. For example, you can wrap each paragraph in a document in a Suspense boundary to regain document streaming capabilities if that's what you want. However, one consideration is if it's worth producing a fallback at all. Maybe if it's like `null` it's free but if it's like a whole alternative page, then it's not. It's possible to have completely useless Suspense boundaries such as when you nest several directly inside each other. So this uses a limit of at least 500 bytes of the content itself for it to be worth outlining at all. It also can't be too small because then for example a long list of paragraphs can never be outlined. In the fixture I straddle this limit so some paragraphs are too small to be considered. An unfortunate effect of that is that you can end up with some of them not being outlined which means that they appear out of order. SuspenseList is supposed to address that but it's unfortunate. The limit is still fairly high though so it's unlikely that by default you'd start outlining anything within the viewport at all. I had to reduce the `progressiveChunkSize` by an order of magnitude in my fixture to try it out properly. DiffTrain build for [18212ca](facebook@18212ca)
Same principle as #33029 but for Flight. We pretty aggressively create separate rows for things in Flight (every Server Component that's an async function create a microtask). However, sync Server Components and just plain Host Components are not. Plus we should ideally ideally inline more of the async ones in the same way Fizz does. This means that we can create rows that end up very large. Especially if all the data is already available. We can't show the parent content until the whole thing loads on the client. We don't really know where Suspense boundaries are for Flight but any Element is potentially a point that can be split. This heuristic counts roughly how much we've serialized to block the current chunk and once a limit is exceeded, we start deferring all Elements. That way they get outlined into future chunks that are later in the stream. Since they get replaced by Lazy references the parent can potentially get unblocked. This can help if you're trying to stream a very large document with a client nav for example.
Same principle as #33029 but for Flight. We pretty aggressively create separate rows for things in Flight (every Server Component that's an async function create a microtask). However, sync Server Components and just plain Host Components are not. Plus we should ideally ideally inline more of the async ones in the same way Fizz does. This means that we can create rows that end up very large. Especially if all the data is already available. We can't show the parent content until the whole thing loads on the client. We don't really know where Suspense boundaries are for Flight but any Element is potentially a point that can be split. This heuristic counts roughly how much we've serialized to block the current chunk and once a limit is exceeded, we start deferring all Elements. That way they get outlined into future chunks that are later in the stream. Since they get replaced by Lazy references the parent can potentially get unblocked. This can help if you're trying to stream a very large document with a client nav for example. DiffTrain build for [49ea8bf](49ea8bf)
) Same principle as facebook#33029 but for Flight. We pretty aggressively create separate rows for things in Flight (every Server Component that's an async function create a microtask). However, sync Server Components and just plain Host Components are not. Plus we should ideally ideally inline more of the async ones in the same way Fizz does. This means that we can create rows that end up very large. Especially if all the data is already available. We can't show the parent content until the whole thing loads on the client. We don't really know where Suspense boundaries are for Flight but any Element is potentially a point that can be split. This heuristic counts roughly how much we've serialized to block the current chunk and once a limit is exceeded, we start deferring all Elements. That way they get outlined into future chunks that are later in the stream. Since they get replaced by Lazy references the parent can potentially get unblocked. This can help if you're trying to stream a very large document with a client nav for example. DiffTrain build for [49ea8bf](facebook@49ea8bf)
) Same principle as facebook#33029 but for Flight. We pretty aggressively create separate rows for things in Flight (every Server Component that's an async function create a microtask). However, sync Server Components and just plain Host Components are not. Plus we should ideally ideally inline more of the async ones in the same way Fizz does. This means that we can create rows that end up very large. Especially if all the data is already available. We can't show the parent content until the whole thing loads on the client. We don't really know where Suspense boundaries are for Flight but any Element is potentially a point that can be split. This heuristic counts roughly how much we've serialized to block the current chunk and once a limit is exceeded, we start deferring all Elements. That way they get outlined into future chunks that are later in the stream. Since they get replaced by Lazy references the parent can potentially get unblocked. This can help if you're trying to stream a very large document with a client nav for example. DiffTrain build for [49ea8bf](facebook@49ea8bf)
Follow up to #33027.
This enhances the heuristic so that we accumulate the size of the currently written boundaries. Starting from the size of the root (minus preamble) for the shell.
This ensures that if you have many small boundaries they don't all continue to get inlined. For example, you can wrap each paragraph in a document in a Suspense boundary to regain document streaming capabilities if that's what you want.
However, one consideration is if it's worth producing a fallback at all. Maybe if it's like
null
it's free but if it's like a whole alternative page, then it's not. It's possible to have completely useless Suspense boundaries such as when you nest several directly inside each other. So this uses a limit of at least 500 bytes of the content itself for it to be worth outlining at all. It also can't be too small because then for example a long list of paragraphs can never be outlined.In the fixture I straddle this limit so some paragraphs are too small to be considered. An unfortunate effect of that is that you can end up with some of them not being outlined which means that they appear out of order. SuspenseList is supposed to address that but it's unfortunate.
The limit is still fairly high though so it's unlikely that by default you'd start outlining anything within the viewport at all. I had to reduce the
progressiveChunkSize
by an order of magnitude in my fixture to try it out properly.